﻿/************************************************************************

   Extended Silverlight Toolkit

   Copyright (C) 2010-2012 Xceed Software Inc.

   This program is provided to you under the terms of the Microsoft Public
   License (Ms-PL) as published at http://extendedsilverlight.codeplex.com/license

   Please purchase a commercial version of this toolkit if you are using
   it in a commercial product. The commercial versions support the project,
   and also include more features for each control, priority support,
   source code, updates, removed watermark, and a proprietary license.

   Visit http://xceed.com and follow @datagrid on Twitter.

  **********************************************************************/

using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using Xceed.Silverlight.Controls;

namespace Xceed.Silverlight.DataGrid
{
  internal abstract class CellContentElementManagerBase
  {
    protected virtual void OnPrepare( FrameworkElement container )
    {
      this.Bind( container, this.TryGetContentTargetProperty, this.TryGetContentSourceBinding );
      this.Bind( container, this.TryGetHorizontalContentAlignmentTargetProperty, this.TryGetHorizontalContentAlignmentSourceBinding );
      this.Bind( container, this.TryGetVerticalContentAlignmentTargetProperty, this.TryGetVerticalContentAlignmentSourceBinding );
      this.Bind( container, this.TryGetTextTrimmingTargetProperty, this.TryGetTextTrimmingSourceBinding );

      this.Bind( container, this.TryGetForegroundTargetProperty, this.TryGetForegroundSourceBinding );
      this.Bind( container, this.TryGetFontFamilyTargetProperty, this.TryGetFontFamilySourceBinding );
      this.Bind( container, this.TryGetFontSizeTargetProperty, this.TryGetFontSizeSourceBinding );
      this.Bind( container, this.TryGetFontStretchTargetProperty, this.TryGetFontStretchSourceBinding );
      this.Bind( container, this.TryGetFontStyleTargetProperty, this.TryGetFontStyleSourceBinding );
      this.Bind( container, this.TryGetFontWeightTargetProperty, this.TryGetFontWeightSourceBinding );
    }

    protected virtual void OnClear( FrameworkElement container )
    {
      this.Unbind( container, this.TryGetContentTargetProperty );
      this.Unbind( container, this.TryGetHorizontalContentAlignmentTargetProperty );
      this.Unbind( container, this.TryGetVerticalContentAlignmentTargetProperty );
      this.Unbind( container, this.TryGetTextTrimmingTargetProperty );

      this.Unbind( container, this.TryGetForegroundTargetProperty );
      this.Unbind( container, this.TryGetFontFamilyTargetProperty );
      this.Unbind( container, this.TryGetFontSizeTargetProperty );
      this.Unbind( container, this.TryGetFontStretchTargetProperty );
      this.Unbind( container, this.TryGetFontStyleTargetProperty );
      this.Unbind( container, this.TryGetFontWeightTargetProperty );
    }

    protected abstract void OnUpdateTargetBinding( FrameworkElement container );

    protected virtual bool TryGetContentTargetProperty(
      FrameworkElement container,
      out DependencyProperty value )
    {
      if( container is NumericTextBox )
      {
        value = NumericTextBox.ValueProperty;
      }
      else if( container is TextBox )
      {
        value = TextBox.TextProperty;
      }
      else if( container is TextBlock )
      {
        value = TextBlock.TextProperty;
      }
      else if( container is ToggleButton )
      {
        value = ToggleButton.IsCheckedProperty;
      }
      else if( container is Selector )
      {
        value = Selector.SelectedValueProperty;
      }
      else if( container is DatePicker )
      {
        value = DatePicker.SelectedDateProperty;
      }
      else if( container is ContentControl )
      {
        value = ContentControl.ContentProperty;
      }
      else
      {
        value = null;
      }

      return ( value != null );
    }

    protected abstract bool TryGetContentSourceBinding(
      FrameworkElement container,
      DependencyProperty targetProperty,
      out Binding binding );

    protected virtual bool TryGetForegroundTargetProperty(
      FrameworkElement container,
      out DependencyProperty value )
    {
      return this.TryGetTargetProperty( container, TextBlock.ForegroundProperty, Control.ForegroundProperty, out value );
    }

    protected abstract bool TryGetForegroundSourceBinding(
      FrameworkElement container,
      DependencyProperty targetProperty,
      out Binding binding );

    protected virtual bool TryGetFontFamilyTargetProperty(
      FrameworkElement container,
      out DependencyProperty value )
    {
      return this.TryGetTargetProperty( container, TextBlock.FontFamilyProperty, Control.FontFamilyProperty, out value );
    }

    protected abstract bool TryGetFontFamilySourceBinding(
      FrameworkElement container,
      DependencyProperty targetProperty,
      out Binding binding );

    protected virtual bool TryGetFontSizeTargetProperty(
      FrameworkElement container,
      out DependencyProperty value )
    {
      return this.TryGetTargetProperty( container, TextBlock.FontSizeProperty, Control.FontSizeProperty, out value );
    }

    protected abstract bool TryGetFontSizeSourceBinding(
      FrameworkElement container,
      DependencyProperty targetProperty,
      out Binding binding );

    protected virtual bool TryGetFontStretchTargetProperty(
      FrameworkElement container,
      out DependencyProperty value )
    {
      return this.TryGetTargetProperty( container, TextBlock.FontStretchProperty, Control.FontStretchProperty, out value );
    }

    protected abstract bool TryGetFontStretchSourceBinding(
      FrameworkElement container,
      DependencyProperty targetProperty,
      out Binding binding );

    protected virtual bool TryGetFontStyleTargetProperty(
      FrameworkElement container,
      out DependencyProperty value )
    {
      return this.TryGetTargetProperty( container, TextBlock.FontStyleProperty, Control.FontStyleProperty, out value );
    }

    protected abstract bool TryGetFontStyleSourceBinding(
      FrameworkElement container,
      DependencyProperty targetProperty,
      out Binding binding );

    protected virtual bool TryGetFontWeightTargetProperty(
      FrameworkElement container,
      out DependencyProperty value )
    {
      return this.TryGetTargetProperty( container, TextBlock.FontWeightProperty, Control.FontWeightProperty, out value );
    }

    protected abstract bool TryGetFontWeightSourceBinding(
      FrameworkElement container,
      DependencyProperty targetProperty,
      out Binding binding );

    protected virtual bool TryGetHorizontalContentAlignmentTargetProperty(
      FrameworkElement container,
      out DependencyProperty value )
    {
      if( container is TextBlock )
      {
        value = TextBlock.TextAlignmentProperty;
      }
      else if( container is ToggleButton )
      {
        value = ToggleButton.HorizontalAlignmentProperty;
      }
      else if( container is Control )
      {
        value = Control.HorizontalContentAlignmentProperty;
      }
      else
      {
        value = null;
      }

      return ( value != null );
    }

    protected abstract bool TryGetHorizontalContentAlignmentSourceBinding(
      FrameworkElement container,
      DependencyProperty targetProperty,
      out Binding binding );

    protected virtual bool TryGetVerticalContentAlignmentTargetProperty(
      FrameworkElement container,
      out DependencyProperty value )
    {
      if( container is TextBlock )
      {
        value = TextBlock.VerticalAlignmentProperty;
      }
      else if( container is ToggleButton )
      {
        value = ToggleButton.VerticalAlignmentProperty;
      }
      else if( container is Control )
      {
        value = Control.VerticalContentAlignmentProperty;
      }
      else
      {
        value = null;
      }

      return ( value != null );
    }

    protected abstract bool TryGetVerticalContentAlignmentSourceBinding(
      FrameworkElement container,
      DependencyProperty targetProperty,
      out Binding binding );

    protected virtual bool TryGetTextTrimmingTargetProperty(
      FrameworkElement container,
      out DependencyProperty value )
    {
      if( container is TextBlock )
      {
        value = TextBlock.TextTrimmingProperty;
      }
      else
      {
        value = null;
      }

      return ( value != null );
    }

    protected abstract bool TryGetTextTrimmingSourceBinding(
      FrameworkElement container,
      DependencyProperty targetProperty,
      out Binding binding );

    internal void Prepare( FrameworkElement container )
    {
      if( container == null )
        return;

      this.OnPrepare( container );
    }

    internal void Clear( FrameworkElement container )
    {
      if( container == null )
        return;

      this.OnClear( container );
    }

    internal void UpdateTargetBinding( FrameworkElement container )
    {
      if( container == null )
        return;

      this.OnUpdateTargetBinding( container );
    }

    private bool TryGetTargetProperty(
      FrameworkElement container,
      DependencyProperty textBlockTargetProperty,
      DependencyProperty controlTargetProperty,
      out DependencyProperty value )
    {
      if( container is TextBlock )
      {
        value = textBlockTargetProperty;
      }
      else if( container is Control )
      {
        value = controlTargetProperty;
      }
      else
      {
        value = null;
      }

      return ( value != null );
    }

    private void Bind(
      FrameworkElement container,
      FindTargetProperty finder,
      CreateBinding creator )
    {
      DependencyProperty targetProperty;
      if( !finder.Invoke( container, out targetProperty ) )
        return;

      Binding binding;
      if( !creator.Invoke( container, targetProperty, out binding ) )
        return;

      var value = container.ReadLocalValue( targetProperty );
      if( value != DependencyProperty.UnsetValue )
        return;

      container.SetBinding( targetProperty, binding );
    }

    private void Unbind( FrameworkElement container, FindTargetProperty finder )
    {
      DependencyProperty targetProperty;
      if( !finder.Invoke( container, out targetProperty ) )
        return;

      container.ClearValue( targetProperty );
    }

    private delegate bool FindTargetProperty( FrameworkElement container, out DependencyProperty value );
    private delegate bool CreateBinding( FrameworkElement container, DependencyProperty target, out Binding value );
  }
}
